
#ifndef _NEBULA_SDK__FUNCAGENT_H_
#define _NEBULA_SDK__FUNCAGENT_H_

#include <vector>

namespace nebula { namespace sdk {

template<typename AGENT_TRAIT>
struct FuncAgentBase
{
	typedef typename AGENT_TRAIT::agent_func_t agent_func_t;
	typedef typename AGENT_TRAIT::host_func_t  host_func_t;

	virtual ~FuncAgentBase() {};
	virtual agent_func_t bind_host(host_func_t val) = 0;
};


template<int N, typename AGENT_TRAIT>
struct FuncAgent;

template<template <int N> class AGENT_TRAIT_PATTERN>
struct FuncAgent<0, AGENT_TRAIT_PATTERN<0> > : FuncAgentBase<AGENT_TRAIT_PATTERN<0> >
{
	typedef AGENT_TRAIT_PATTERN<0>      pattern_type;
	typedef AGENT_TRAIT_PATTERN<0>      agent_type;
	typedef FuncAgent<0, pattern_type>  this_type;	
	typedef FuncAgentBase<pattern_type> base_type;
	typedef FuncAgent<0, pattern_type>  prev_type;

	typedef typename pattern_type::agent_func_t agent_func_t;
	typedef typename pattern_type::host_func_t  host_func_t;

	FuncAgent(std::vector<base_type*>& agent_vec)
	{
		agent_vec.push_back(this);
	}

	agent_func_t bind_host(host_func_t val)
	{
		if (agent_type::host(0))
			return 0;

		agent_type::host(val);
		return agent_type::agent;
	}
};

template<int N, template <int _N> class AGENT_TRAIT_PATTERN>
struct FuncAgent<N, AGENT_TRAIT_PATTERN<N> > : FuncAgentBase<AGENT_TRAIT_PATTERN<0> >
{
	typedef AGENT_TRAIT_PATTERN<0>      pattern_type;
	typedef AGENT_TRAIT_PATTERN<N>      agent_type;
	typedef FuncAgent<N, pattern_type>  this_type;	
	typedef FuncAgentBase<pattern_type> base_type;
	typedef FuncAgent<N - 1, AGENT_TRAIT_PATTERN<N - 1> >  prev_type;

	typedef typename pattern_type::agent_func_t agent_func_t;
	typedef typename pattern_type::host_func_t  host_func_t;

	prev_type _prev;

	FuncAgent(std::vector<base_type*>& agent_vec):
		_prev(agent_vec)
	{
		agent_vec.push_back(this);
	}

	agent_func_t bind_host(host_func_t val)
	{
		if (agent_type::host(0))
			return 0;

		agent_type::host(val);
		return agent_type::agent;
	}
};

template<int N, template <int _N> class AGENT_TRAIT_PATTERN>
struct FuncAgentWrapper
{
	typedef AGENT_TRAIT_PATTERN<0> pattern_type;
	typedef FuncAgent<N, AGENT_TRAIT_PATTERN<N> > agent_type;

	typedef FuncAgentBase<pattern_type> agent_base_t;
	typedef std::vector<agent_base_t*>  agent_vec_t;
	
	typedef typename pattern_type::agent_func_t agent_func_t;
	typedef typename pattern_type::host_func_t  host_func_t;

	int         _curid;
	agent_vec_t _agent_vec;
	agent_type  _agents;

	FuncAgentWrapper() :
		_curid(0), _agents(_agent_vec)
	{
	}

	agent_func_t GetAgent(host_func_t host)
	{
		unsigned id = _curid + 1;
		if (id >= _agent_vec.size())
			return 0;

		++_curid;

		return _agent_vec[id]->bind_host(host);
	}

};

}} // end of nebula::sdk

#endif // _NEBULA_SDK__FUNCAGENT_H_


